home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / ncsat.cpt / Telnet2.5 final / tcpip / tools.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  13.3 KB  |  568 lines

  1. /*
  2. *      TOOLS.C
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/IP kernel for NCSA Telnet                                       *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  16. *                                                                          *
  17. ****************************************************************************
  18. *
  19. *  Portions of the driver code that are not specific to a particular protocol
  20. *
  21. */
  22. #include <stdio.h>
  23. #include "protocol.h"
  24. #include "data.h"
  25. #include "mactools.h"
  26. #include "tcp.h"
  27.  
  28. #include <Events.h>
  29. #include <ToolUtils.h>    /* BYU 2.4.16 MPW - for GetIndString() */
  30. #include <String.h>
  31. #include <Strings.h>    /* BYU 2.4.16 MPW - for p2cstr() */
  32.  
  33. extern short slip_connection;        /* BYU 2.4.15 */
  34.  
  35. /***************************************************************************/
  36. /*  enqueue
  37. *   add something to a TCP queue.  Used by both 'write()' and tcpinterpret
  38. *   WINDOWSIZE is the size limitation of the advertised window.
  39. */
  40. int enqueue
  41.   (
  42.     struct window *wind,
  43.     char *buffer,
  44.     int nbytes
  45.   )
  46.     {
  47.     int i;
  48.     
  49.     i = WINDOWSIZE - wind->contain;
  50.     if (i <= 0 || nbytes == 0)
  51.         return(0);                        /* no room at the inn */
  52.  
  53.     if (nbytes > i)
  54.         nbytes = i;
  55.  
  56.     i = wind->where - wind->endlim;        /* room at end */
  57.     i += WINDOWSIZE;
  58.  
  59.     if (i < nbytes) {
  60.         movebytes(wind->endlim,buffer,i);
  61.         movebytes(wind->where,(char *)(buffer+i),nbytes-i);
  62.         wind->endlim = wind->where + nbytes - i;
  63.     } 
  64.     else {
  65.         movebytes(wind->endlim,buffer,nbytes);        /* fits in one chunk */
  66.         wind->endlim += nbytes;
  67.     }
  68.     wind->contain += nbytes;            /* more stuff here */
  69.  
  70.     return(nbytes);
  71.  
  72. }
  73.  
  74. /*************************************************************************/
  75. /* dequeue
  76. *     used by read, this copies data out of the queue and then
  77. *  deallocates it from the queue.
  78. *  cpqueue and rmqueue are very similar and are to be used by tcpsend
  79. *  to store unacknowledged data.
  80. *
  81. *  returns number of bytes copied from the queue
  82. */
  83. int dequeue
  84.   (
  85.     struct window *wind,
  86.     char *buffer,
  87.     int nbytes                /* maximum number to copy out */
  88.   )
  89.     {
  90.     int i;
  91.  
  92.     if (wind->contain == 0)
  93.         return(0);
  94.  
  95.     if (wind->contain < nbytes)
  96.         nbytes = wind->contain;
  97.  
  98.     i = wind->endbuf - wind->base;
  99.  
  100.     if (i <= nbytes) {
  101.         movebytes(buffer,wind->base,i);
  102.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  103.         wind->base = wind->where + nbytes-i;
  104.     }
  105.     else {
  106.         movebytes( buffer, wind->base, nbytes);
  107.         if (wind->contain == nbytes) 
  108.             wind->base = wind->endlim = wind->where;
  109.         else
  110.             wind->base += nbytes;
  111.     }
  112.     
  113.     wind->contain -= nbytes;
  114.  
  115.     return(nbytes);
  116.  
  117. }
  118.  
  119. #ifdef notneeded
  120. /**************************************************************************/
  121. /*  cpqueue
  122. *       does the same thing as dequeue, but does not deallocate the data
  123. *   used when transmitting TCP data.  When the data is ACKed, then 
  124. *   rmqueue is called to deallocate the correct amount of data.
  125. */
  126. cpqueue(wind,buffer,nbytes)
  127.     struct window *wind;
  128.     char *buffer;
  129.     int nbytes;                /* maximum number to copy out */
  130.     {
  131.     int i;
  132.  
  133.     if (wind->contain == 0)
  134.         return(0);
  135.  
  136.     if (wind->contain < nbytes)
  137.         nbytes = wind->contain;
  138.  
  139.     i = wind->endbuf - wind->base;
  140.  
  141.     if (i < nbytes) {
  142.         movebytes(buffer,wind->base,i);
  143.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  144.     }
  145.     else 
  146.         movebytes( buffer, wind->base, nbytes);
  147.     
  148.     return(nbytes);
  149.  
  150. }
  151. #endif
  152.  
  153. /**************************************************************************/
  154. /*  rmqueue
  155. *     does the queue deallocation that is left out of cpqueue
  156. *
  157. *   rmqueue of WINDOWSIZE or greater bytes will empty the queue
  158. */
  159. int rmqueue
  160.   (
  161.     struct window *wind,
  162.     int nbytes                    /* number to remove */
  163.   )
  164.     {
  165.     int i;
  166.  
  167.     if (wind->contain < nbytes)
  168.         nbytes = wind->contain;
  169.  
  170.     i = wind->endbuf - wind->base;
  171.  
  172.     if (i <= nbytes) 
  173.         wind->base = wind->where+nbytes-i;
  174.     else {
  175.         if (wind->contain == nbytes)
  176.             wind->base = wind->endlim = wind->where;
  177.         else
  178.             wind->base += nbytes;
  179.     }
  180.     
  181.     wind->contain -= nbytes;
  182.  
  183.     return(nbytes);
  184.  
  185. }
  186.  
  187.  
  188. /************************************************************************/
  189. /* comparen
  190. *  Take n bytes and return identical (true=1) or not identical (false=0)
  191. *
  192. *  Could be written in assembler for improved performance
  193. */
  194. int comparen
  195.   (
  196.     uint8 *s1,
  197.     uint8 *s2,
  198.     register int n
  199.   )
  200.     {
  201.  
  202.     while (n--)
  203.         if (*s1++ != *s2++)
  204.             return(0);
  205.  
  206.     return(1);
  207.  
  208. }
  209.  
  210. /***********************************************************************/
  211. /*  netgetevent
  212. *   Retrieves the next event (and clears it) which matches bits in
  213. *   the given mask.  Returns the event number or -1 on no event present.
  214. *   Also returns the exact class and the associated integer in reference
  215. *   parameters.
  216. *
  217. *   The way the queue works:
  218. *     There is always a dummy record pointed to by nnelast.
  219. *     When data is put into the queue, it goes into nnelast, then nnelast
  220. *        looks around for another empty one to obtain.
  221. *        It looks at nnefree first, then bumps one from nnefirst if necessary.
  222. *     When data is retrieved, it is searched from nnefirst to nnelast.
  223. *        Any freed record is appended to nnefree.
  224. */
  225. int netgetevent
  226.   (
  227.     uint8 mask,
  228.     int *retclass,
  229.     int *retint
  230.   )
  231.     {
  232.     int i,j;
  233.  
  234.     i = j = nnefirst;
  235.  
  236.     while (i != nnelast) {
  237.         if (mask & nnq[i].eclass) {
  238.             if (i == nnefirst) 
  239.                 nnefirst = nnq[nnefirst].next;        /* step nnefirst */
  240.             else 
  241.                 nnq[j].next = nnq[i].next;            /* bypass record i */
  242.  
  243.             nnq[i].next = nnefree;
  244.             nnefree = i;                            /* install in free list */
  245.             *retint = nnq[i].idata;
  246.             *retclass = nnq[i].eclass;
  247.             return(nnq[i].event);
  248.         }
  249.         j = i;
  250.         i = nnq[i].next;
  251.     }
  252.  
  253.     return(0);
  254.  
  255. }
  256.  
  257. /***********************************************************************/
  258. /*  netputevent
  259. *   add an event to the queue.
  260. *   Will probably get the memory for the entry from the free list.
  261. *   Returns 0 if there was room, 1 if an event was lost.
  262. */
  263. int netputevent
  264.   (
  265.     int class,
  266.     int what,
  267.     int dat
  268.   )
  269.     {
  270.     int i; 
  271.     
  272.     i = nnelast;
  273.     nnq[i].eclass = class;                    /* put data in */
  274.     nnq[i].event = what;
  275.     nnq[i].idata = dat;
  276.  
  277.     if (nnefree >= 0) {                        /* there is a spot in free list */
  278.         nnq[i].next = nnelast = nnefree;
  279.         nnefree = nnq[nnefree].next;        /* remove from free list */
  280.         return(0);
  281.     }
  282.     else {
  283.         nnq[i].next = nnelast = nnefirst;
  284.         nnefirst = nnq[nnefirst].next;        /* lose oldest event */
  285.         return(1);
  286.     }
  287. }
  288.  
  289. /***************************************************************************/
  290. /*  netputuev
  291. *   put a unique event into the queue
  292. *   First searches the queue for like events
  293. */
  294. int netputuev
  295.   (
  296.     int class,
  297.     int what,
  298.     int dat
  299.   )
  300.     {
  301.     int i;
  302.  
  303.     i = nnefirst;
  304.     while (i != nnelast) {
  305.         if (nnq[i].idata == dat && nnq[i].event == what &&
  306.             nnq[i].eclass == class)
  307.             return(0);
  308.         i = nnq[i].next;
  309.     }
  310.  
  311.     return(netputevent(class,what,dat));
  312.  
  313. }
  314.  
  315. /************************************************************************/
  316. /*  netposterr
  317. *   place an error into the event q
  318. *   Takes the error number and puts it into the error structure
  319. */
  320. void netposterr
  321.   (
  322.     int num
  323.   )
  324.   {
  325.  
  326.     if (netputevent(ERRCLASS,ERR1,num))
  327.  
  328.         netputuev(ERRCLASS,ERR1,501);            /* only if we lost an event */
  329.   }
  330.  
  331. /************************************************************************/
  332. /*  transq
  333. *
  334. *   Needed for TCP, not as general as cpqueue, 
  335. *   but is required for efficient uploading
  336. *
  337. *   Transmit the entire queue (window) to the other host without expecting
  338. *   any sort of acknowledgement.
  339. *
  340. */
  341. int transq
  342.   (
  343.     struct port *prt
  344.   )
  345.     {
  346.     uint bites;
  347.     int i,j,n;
  348.     struct window *wind;
  349.     uint32 saveseq;
  350.     uint8 *endb,*whereb,*baseb;
  351.  
  352.     if (prt == NULL) {
  353.         nnerror(406);        /* NULL port for trans */
  354.         return(-1);
  355.     }
  356.  
  357.     wind = &prt->out;
  358. /*
  359. *   find out how many bytes the other side will allow us to send (window)
  360. */
  361.     bites = wind->size;
  362.     if (wind->contain < bites)
  363.         bites = wind->contain;
  364.  
  365. /*
  366. *  set up the tcp packet for this, ACK field is same for all packets
  367. */
  368.     prt->tcpout.t.ack = longswap(prt->in.nxt);
  369. /*
  370. *  any more flags should be set?
  371. */
  372.     if (wind->push) {                    /* is push indicator on? */
  373.         prt->tcpout.t.flags |= TPUSH;
  374.         wind->push = 0;
  375.     }
  376.  
  377.     if ((bites <= 0) || prt->state != SEST) {    /* if no data to send . . . */
  378.         tcpsend(prt,0);                /* just a retransmission or ACK */
  379.         return(0);
  380.     }
  381.  
  382. /*
  383. *  we have data to send, get the correct sequence #'s 
  384. */
  385.     saveseq = wind->nxt;
  386.  
  387.     whereb = wind->where;
  388.     endb = wind->endbuf;
  389.     baseb = wind->base;
  390. /*
  391. *  in a loop, transmit the entire queue of data 
  392. */
  393.     for (i=0 ; i < bites; i += prt->sendsize) {
  394.         n = prt->sendsize;
  395.         if (i + n > bites)
  396.             n = bites - i;
  397.  
  398.         j = endb - baseb;
  399.  
  400.         if (j < n) {
  401.             movebytes(prt->tcpout.x.data,baseb,j);
  402.             movebytes((char *)(prt->tcpout.x.data+j),whereb,n-j);
  403.             baseb = whereb + n-j;
  404.         }
  405.         else {
  406.             movebytes( prt->tcpout.x.data, baseb, n);
  407.             baseb += n;
  408.         }
  409.  
  410.         tcpsend(prt,n);                        /* send it */
  411.         wind->nxt += n;
  412.     }
  413.  
  414.     wind->nxt = saveseq;                    /* get back first seq # */
  415.  
  416.     return(0);
  417. } /* transq */
  418.  
  419. /************************************************************************/
  420. /*  netsleep
  421. *      sleep, while demuxing packets, so we don't miss anything
  422. *
  423. */
  424. int netsleep
  425.   (
  426.     int n
  427.   )
  428.     {
  429.     int i,nmux,redir;
  430.     int32 t,gt,start;
  431.     struct port *p;
  432.     uint8 *pc;
  433.  
  434.     redir = 0;
  435.     start = time(NULL);
  436.  
  437.     if (n)
  438.         t = start + n*TICKSPERSEC;
  439.     else
  440.         t = start;
  441.  
  442.     do {
  443.         nmux = demux(1);                /* demux all packets */
  444.  
  445. /*
  446. *  if there were packets in the incoming packet buffer, then more might
  447. *  have arrived while we were processing them.  This gives absolute priority
  448. *  to packets coming in from the network.
  449. */
  450.         if (nmux)
  451.             continue;
  452.  
  453.         if (IREDIR == netgetevent(ICMPCLASS,&i,&i))
  454.             redir = 1;
  455. /*
  456. *  Check each port to see if action is necessary.
  457. *  This now sends all Ack packets, due to p->lasttime being set to 0L.
  458. *  Waiting for nmux == 0 for sending ACKs makes sure that the network
  459. *  has a much higher priority and reduces the number of unnecessary ACKs.
  460. */
  461.         gt = time(NULL);
  462.  
  463.         for (i=0; i < NPORTS; i++) {
  464.             p = portlist[i];
  465.  
  466.             if ((p->type == 1) && !slip_connection)            /* BYU 2.4.15 */
  467.                 continue;                                    /* BYU 2.4.15 */
  468.  
  469.             if ((p != NULL) && (p->state > SLISTEN)) {
  470.  
  471.                 if (!p->out.lasttime) 
  472.                     transq(p);                /* takes care of all ACKs */
  473.  
  474.                 else if ((p->out.contain > 0) || (p->state > SEST)) {
  475. /*
  476. *  if a retransmission timeout occurs, exponential back-off.
  477. *  This number returns toward the correct value by the RTT measurement
  478. *  code in ackcheck.
  479. *
  480. *  fix: 5/12/88, if timer was at MAXRTO, transq didn't get hit - TK
  481. */
  482.                     if ((p->out.lasttime + p->rto < gt)) {
  483.                         if (p->rto < MAXRTO) 
  484.                             p->rto <<= 1;        /* double it */
  485.                         transq(p);
  486.                     }
  487.                 }
  488.  
  489.                 if ((p->out.lasttime + POKEINTERVAL < gt) && 
  490.                     (p->state == SEST))
  491.                     transq(p);
  492. /*
  493. *  check to see if ICMP redirection occurred and needs servicing.
  494. *  If it needs servicing, try to get the new hardware address for the new 
  495. *  gateway.  If an arp was sent during getdlayer, we assume another ICMP
  496. *  redirect will occur, this routine will reactivate, and then the hardware
  497. *  address will be available in the cache.
  498. */
  499.                 if (redir && comparen(p->tcpout.i.ipdest,nnicmpsave,4)) {
  500.                     pc = getdlayer(nnicmpnew);
  501.                     if (pc != NULL)
  502.                         movebytes(p->tcpout.d.dest,pc,DADDLEN);
  503.                 }
  504.             }
  505.         }
  506.         redir = 0;                /* reset flag for next demux */
  507.  
  508.     } while ((t > time(NULL))         /* done yet? */
  509.         && (time(NULL) >= start));  /* allow for wraparound of timer */
  510.  
  511.  
  512.     return(nmux);                /* will demux once, even for sleep(0) */
  513.  
  514. } /* netsleep */
  515.  
  516. #define ERROR_RESOURCE_ID 23237        /* BYU 2.4.16 */
  517. #define ERROR_RESOURCE_COUNT 52        /* BYU 2.4.16 */
  518.  
  519. #if 0                                /* BYU 2.4.16 */
  520. /************************************************************************/
  521. /*  neterrstring
  522. *   returns the string associated with a particular error number
  523. *
  524. *   error number is formatted %4d at the beginning of the string
  525. */
  526. static char *errs[] = {"   0 Error unknown",
  527.             " 100 ...",            /* BYU 2.4.16 - strings moved to resource # 23237 */
  528.                         ""};
  529. #endif                            /* BYU 2.4.16 */
  530.  
  531. static char errspace[80];        /* room for user-defined errors */
  532.  
  533. char *neterrstring(errno)
  534.     int errno;
  535.     {
  536.     int i;
  537.     char s[10];
  538.     Str255 ErrorString;                                    /* BYU 2.4.16 */
  539.  
  540.     if (errno < 0) 
  541.         return(errspace);
  542.  
  543.     sprintf(s,"%4d",errno);
  544.  
  545. #if 1                                                    /* BYU 2.4.16 */
  546.     for (i=1; i<=ERROR_RESOURCE_COUNT; i++) {            /* BYU 2.4.16 */
  547.         GetIndString(ErrorString,ERROR_RESOURCE_ID,i);    /* BYU 2.4.16 */
  548.         p2cstr(ErrorString);                            /* BYU 2.4.16 */
  549.         if (!strncmp((char *) ErrorString,s,4))            /* BYU 2.4.16 */
  550.             return((char *) ErrorString + 5);            /* BYU 2.4.16 - pointer to error message  */
  551.     }                                                    /* BYU 2.4.16 */
  552.  
  553.     GetIndString(ErrorString,ERROR_RESOURCE_ID,1);        /* BYU 2.4.16 */
  554.     return((char *) ErrorString+5);                        /* BYU 2.4.16 - pointer to error message  */
  555. #else                                                    /* BYU 2.4.16 */
  556.     i = 0;
  557.     do {
  558.         if (!strncmp(errs[i],s,4))
  559.             return(errs[i]+5);            /* pointer to error message  */
  560.         i++;
  561.  
  562.     } while (*errs[i] || i > 100);            /* until NULL found */
  563.  
  564.     return(errs[0]+5);                    /* error unknown */
  565. #endif                                        /* BYU 2.4.16 */
  566. }
  567.  
  568.